package net.solvetheriddle.wwclient;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import android.util.Log;

import net.solvetheriddle.wwclient.entity.Project;
import net.solvetheriddle.wwclient.entity.User;
import net.solvetheriddle.wwclient.entity.Work;

/**
 * @author anoniim
 *
 */
public class WWParser {

    private static final String ELEMENT_USER = "pracovnik";
    private static final String ELEMENT_PROJECT = "zakazka";
    private static final String ELEMENT_WORK = "prace";
    private static final String ELEMENT_PROJECT_NAME = "nazev";
    private static final String ELEMENT_PROJECT_OPEN = "splneno";
    private static final String ELEMENT_FIRSTNAME = "jmeno";
    private static final String ELEMENT_SURENAME = "prijmeni";
    private static final String ELEMENT_SALLARY = "plat";
    private static final String ELEMENT_ID = "id";
    private static final String ELEMENT_PROJECT_ID = "id-zakazky";
    private static final String ELEMENT_WORK_DESCRIPTION = "popis";
    private static final String ELEMENT_BEGIN_TIME = "od";
    private static final String ELEMENT_END_TIME = "do";
    private static final String ELEMENT_DATE = "datum";

    public static final long ONE_DAY_IN_MILLIS = 86400000;
    public static final long ONE_HOUR_IN_MILLIS = 3600000;
    public static final long MINUTE_15_IN_MILLIS = 900000;
    private static SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
    private static SimpleDateFormat timeFormat = new SimpleDateFormat("HH:mm:ss");

    public static User parseUserFromStream(InputStream userInputStream) {
        if (userInputStream != null) {
            Document userXMLDcoument = null;
            try {
                DocumentBuilder db = DocumentBuilderFactory.newInstance().newDocumentBuilder();
                userXMLDcoument = db.parse(userInputStream);
            } catch (Exception e) {
                Log.e("WWCLIENT", "! Exception while parsing XML file:");
                e.printStackTrace();
            }
            return getUserFromXML(userXMLDcoument);
        }
        return null;
    }

    /**
     * Parses the given XML file for the User entitiy.
     * 
     * @param dom
     *            document to parse
     * @return User entitiy
     */
    private static User getUserFromXML(Document userDom) {
        if (userDom != null) {
            Element docElement = userDom.getDocumentElement();
            // get ID
            Element userElement = (Element) docElement.getElementsByTagName(ELEMENT_USER).item(0);
            int id = Integer.parseInt(userElement.getAttribute("id"));
            // get first name
            Element firstnameElement = (Element) docElement.getElementsByTagName(ELEMENT_FIRSTNAME).item(0);
            String firstName = firstnameElement.getFirstChild().getNodeValue().replaceAll("\\n", "");
            // get surname
            Element surenameElement = (Element) docElement.getElementsByTagName(ELEMENT_SURENAME).item(0);
            String surname = surenameElement.getFirstChild().getNodeValue().replaceAll("\\n", "");
            // get salary
            Element sallaryElement = (Element) docElement.getElementsByTagName(ELEMENT_SALLARY).item(0);
            String sallaryString = sallaryElement.getFirstChild().getNodeValue().replaceAll("\\n", "");
            int salary = Integer.parseInt(sallaryString);
            // return new instance of User
            return new User(id, firstName, surname, salary);
        }
        return null;
    }

    public static List<Project> parseProjectsFromStream(InputStream projectsInputStream) {
        if (projectsInputStream != null) {
            Document openProjectsXMLDcoument = null;
            try {
                DocumentBuilder db = DocumentBuilderFactory.newInstance().newDocumentBuilder();
                openProjectsXMLDcoument = db.parse(projectsInputStream);
            } catch (Exception e) {
                Log.e("WWCLIENT", "! Exception while parsing XML file:" + e.toString());
                e.printStackTrace();
            }
            return getProjectsFromXML(openProjectsXMLDcoument);
        }
        return new ArrayList<Project>();
    }

    /**
     * Parses the given XML file for the Project entity.
     * 
     * @param projectsDom
     *            document to parse
     * @return Project entity
     */
    private static List<Project> getProjectsFromXML(Document projectsDom) {
        List<Project> projects = new ArrayList<Project>();
        if (projectsDom != null) {
            Element docElement = projectsDom.getDocumentElement();
            NodeList projectsNodeList = (NodeList) docElement.getElementsByTagName(ELEMENT_PROJECT);
            for (int i = 0; i < projectsNodeList.getLength(); i++) {
                Element projectElement = (Element) projectsNodeList.item(i);
                // get project ID
                int id = Integer.parseInt(projectElement.getAttribute("id"));
                // get project name
                Element projectNameElement = (Element) projectElement.getElementsByTagName(ELEMENT_PROJECT_NAME).item(0);
                String projectName = projectNameElement.getFirstChild().getNodeValue().replaceAll("\\n", "");
                // is open
                Element projectOpenElement = (Element) projectElement.getElementsByTagName(ELEMENT_PROJECT_OPEN).item(0);
                String projectDone = projectOpenElement.getFirstChild().getNodeValue().replaceAll("\\n", "");
                boolean isOpen = projectDone.equals("n");
                // add new project to set
                projects.add(new Project(id, projectName, new ArrayList<Work>(), isOpen));
            }
        }
        // return all open projects
        return projects;
    }

    public static List<Work> parseWorkFromStream(InputStream workStream) {
        Document workXMLDcoument = null;
        try {
            DocumentBuilder db = DocumentBuilderFactory.newInstance().newDocumentBuilder();
            workXMLDcoument = db.parse(workStream);
        } catch (Exception e) {
            Log.e("WWCLIENT", "! Exception while parsing XML file:");
            e.printStackTrace();
        }
        return getWorkFromXML(workXMLDcoument);
    }

    /**
     * Parses the given XML file for the Work entity.
     * 
     * @param workDom
     *            document to parse
     * @return
     */
    private static List<Work> getWorkFromXML(Document workDom) {
        List<Work> works = new ArrayList<Work>();
        if (workDom != null) {
            NodeList workNodeList = (NodeList) workDom.getElementsByTagName(ELEMENT_WORK);
            for (int i = 0; i < workNodeList.getLength(); i++) {
                Element workElement = (Element) workNodeList.item(i);
                // get work ID
                int id = Integer.parseInt(workElement.getAttribute(ELEMENT_ID));
                // get project ID
                int projectID = Integer.parseInt(workElement.getAttribute(ELEMENT_PROJECT_ID));
                // get work description
                Element workDescriptionElement = (Element) workElement.getElementsByTagName(ELEMENT_WORK_DESCRIPTION).item(0);
                Node node = workDescriptionElement.getFirstChild();
                String workDescription;
                if (node == null) {
                    workDescription = "";
                } else {
                    workDescription = node.getNodeValue().replaceAll("\\n", "");
                }
                // get beginTime
                Element beginTimeElement = (Element) workElement.getElementsByTagName(ELEMENT_BEGIN_TIME).item(0);
                String beginTimeString = beginTimeElement.getFirstChild().getNodeValue().replaceAll("\\n", "");
                long beginTime = stringToTime(beginTimeString);
                // get endTime
                Element endTimeElement = (Element) workElement.getElementsByTagName(ELEMENT_END_TIME).item(0);
                String endTimeString = endTimeElement.getFirstChild().getNodeValue().replaceAll("\\n", "");
                long endTime = stringToTime(endTimeString);
                // get date
                Element dateElement = (Element) workElement.getElementsByTagName(ELEMENT_DATE).item(0);
                String dateString = dateElement.getFirstChild().getNodeValue().replaceAll("\\n", "");
                long dateInMillis = stringToDate(dateString);
                // TODO This needs to be fixed hard. 
                beginTime += dateInMillis + ONE_HOUR_IN_MILLIS;
                endTime += dateInMillis + ONE_HOUR_IN_MILLIS;
                // add new Work to the list
                works.add(new Work(id, projectID, workDescription, beginTime, endTime));
            }
        }
        return works;
    }
    
    public static String parseStringFromStream(InputStream stream) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(stream));
        StringBuilder sb = new StringBuilder();
        String line = null;
        while ((line = br.readLine()) != null) {
            sb.append(line + "\n");
        }
        br.close();
        return sb.toString();
    }

    public static long stringToDate(String dateString) {
        try {
            return dateFormat.parse(dateString).getTime();
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return 0;
    }

    public static long stringToTime(String timeString) {
        try {
            return timeFormat.parse(timeString).getTime();
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return 0;
    }
    
    public static String longToDate(long dateLong) {
        return dateFormat.format(new Date(dateLong));
    }

    public static String longToTime(long timeLong) {
        return timeFormat.format(new Date(timeLong));
    }
}
